﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Net.Sockets;
using System.Net;
using System.Threading;


namespace TCPServer
{
    class Program
    {
        static object _lock = new object();

        static void Main (string [] args)
        {
            int puerto = int.Parse  (args[0]);
            Console.WriteLine       ("HAV");
            Console.Out.WriteLine   ("TCP Server tratando de iniciar en puerto {0}", puerto);
            Servidor servidor       = new Servidor ();
            servidor.clienteAceptado+= new ClienteAceptado (servidor_clienteAceptado);
            servidor.iniciar        (int.Parse(args[0]));
            Console.ForegroundColor = ConsoleColor.Green;
            Console.Out.WriteLine   ("TCP Server iniciado en puerto {0} !", puerto);
            Console.ForegroundColor = ConsoleColor.Gray;
            Console.Out.WriteLine   ("TCP Server escuchando ", puerto);

            while ( "exit" != Console.ReadLine().Trim().ToLower() )
                ;
        }

        static void servidor_clienteAceptado (object sender, ClienteAceptadoEventArgs evargs)
        {
            var ip          = ((IPEndPoint)evargs.cliente.Client.RemoteEndPoint).Address;
            var puerto      = ((IPEndPoint)evargs.cliente.Client.RemoteEndPoint).Port;

            Console.WriteLine ("Cliente aceptado desde {0}:{1} ", ip, puerto);

            Thread t        = new Thread (new ParameterizedThreadStart(f));
            t.IsBackground  = true;
            t.Name          = string.Format ("{0}:{1}", ip, puerto);
            t.Start         (evargs.cliente);
        }

        static void f (object param)
        {
            TcpClient cliente = (TcpClient) param;

            try
            {
                using (NetworkStream ns = cliente.GetStream())
                {
                    ns.WriteTimeout = 25 * 1000;
                    ns.ReadTimeout  = 25 * 1000;

                    var bytesAcum   = new List<byte>();
                    var @byte       = 0;
                    
                    while (-1 != (@byte = ns.ReadByte()))
                    {
                        bytesAcum.Add ((byte) @byte);

                        if (@byte == (int) ';')
                        {
                            string cadenaRecibida = Encoding.ASCII.GetString (bytesAcum.ToArray()); 
                            bytesAcum.Clear();

                            if (! manejarRecepcion(cadenaRecibida.Trim(), ns))
                                break;
                        }

                        if ((@byte == 255) || (bytesAcum.Count > 200))
                        {
                            break;
                        }
                    }

                    try { if (ns != null) ns.Close(); } catch { }
                }
            }
            catch (Exception exx)
            {
                manejarExcepcion (exx);
            }
            finally
            {
                try { if (cliente != null) cliente.Close(); } catch { }
            }
        }

        static void manejarExcepcion (Exception exx)
        {
            //
        }

        static bool manejarRecepcion (string cadenaRecibida, NetworkStream ns)
        {
            if (Regex.IsMatch (cadenaRecibida, "^imei:[0-9]{10,},tracker"))
            {
                var buff = Encoding.ASCII.GetBytes ("**,imei:" + dameImei(cadenaRecibida) + ",C,10s");
                ns.Write (buff, 0, buff.Length);
                ns.Flush ();
                return true;
            }

            if (Regex.IsMatch (cadenaRecibida, "^##,imei:[0-9]{10,},A;$"))
            {
                var buff = Encoding.ASCII.GetBytes ("LOAD");
                ns.Write (buff, 0, buff.Length);
                ns.Flush ();
                return true;
            }

            if (Regex.IsMatch (cadenaRecibida, "^[0-9]{10,};$"))
            {
                var buff = Encoding.ASCII.GetBytes ("ON");
                ns.Write (buff, 0, buff.Length);
                ns.Flush ();
                return true;
            }

            //help me
            //low battery
            //stockade
            //move
            //speed
            //dt
            //et
            //gt
            //ht
            //it
            //nt

            // salgo por no tener respuesta para el comando: cadenaRecibida...
            return false;
        }

        static string dameImei (string s)
        {
            Match match = Regex.Match (s, "imei:[0-9]{10,}");

            return match.Success ?
                match.Value.Split(':')[1]   :
                string.Empty                ;
        }

        static void mostrar (string s)
        {
            lock (_lock)
                Console.WriteLine(System.DateTime.Now.ToString() + s);
        }
    }
}
